package spc.webos.util.http;

import java.io.ByteArrayOutputStream;

import spc.webos.util.StringX;

public class HTTPUtil
{
	public static byte[] HTTP_RESPONSE_HEADER = "HTTP/1.1 200 OK\r\n".getBytes();
	static byte[] HTTP_HEADER_CONTENT_LENGTH = "Content-Length:".getBytes();
	static byte[] HTTP_HEAD_DELIM = "\r\n".getBytes();
	static byte[] HTTP_PROTOCOL_10 = "HTTP/1.0".getBytes();
	static byte[] HTTP_POST = "POST".getBytes();

	// public static void main(String[] args) throws Exception
	// {
	// String str =
	// "UE9TVCAvSU4vd3MvaHR0cHNvYXAgSFRUUC8xLjENCkNvbm5lY3Rpb246IEtlZXAtQWxpdmUNClVzZXItQWdlbnQ6IEpha2FydGEgQ29tbW9ucy1IdHRwQ2xpZW50LzMuMA0KSG9zdDogMTI3LjAuMC4xOjMzMjAwDQpDb250ZW50LUxlbmd0aDogMTUyOQ0KDQo8c29hcGVudjpFbnZlbG9wZSB4bWxuczpzb2FwZW52PSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9zb2FwL2VudmVsb3BlLyIgeG1sbnM6cG9ydD0iaHR0cDovL3d3dy5pYm0uY29tL3Byb2plY3QvY2l0aWMvZWNpZi9jaXRpY3BhcnR5YnAvcG9ydCI+DQogICA8c29hcGVudjpIZWFkZXIvPg0KICAgPHNvYXBlbnY6Qm9keT4NCiAgICAgIDxwb3J0OkFkZEV2YWx1YXRlSW5mbz4NCiAgICAgICAgIDxjb250cm9sPg0KICAgICAgICAgICAgPHVzZXJSZXNlcnZlPjwvdXNlclJlc2VydmU+DQoJCQk8b3ByVHlwZT4wMTwvb3ByVHlwZT4NCgkJCTxyY3ZPcmdDb2RlPjAwMDAwMDAwMDAwMjwvcmN2T3JnQ29kZT4NCgkJCTxzbmRUcmFuVGltZT4wMTAxMDE8L3NuZFRyYW5UaW1lPg0KCQkJPGNvbW1SZXNlcnZlPjAwMDAwMDAxPC9jb21tUmVzZXJ2ZT4NCgkJCTxjaGFuRmxhZz4wMzwvY2hhbkZsYWc+DQoJCQk8dHJhblR5cGU+MjwvdHJhblR5cGU+DQoJCQk8bXNnVHlwZUNvZGU+U0VUMDA5PC9tc2dUeXBlQ29kZT4NCgkJCTxzZXREYXRlPjIwMTIwODAxPC9zZXREYXRlPg0KCQkJPG9yaU9wclR5cGU+PC9vcmlPcHJUeXBlPg0KCQkJPG1zZ1JlZk5vPjAxMjA4MDEwMDAwMDAwMDAwMDEwMTAwMDAwMDAwMDAwMTwvbXNnUmVmTm8+DQoJCQk8cmVzZXJ2ZT48L3Jlc2VydmU+DQoJCQk8c25kT3JnQ29kZT4wMDAwMDAwMDAwMDE8L3NuZE9yZ0NvZGU+DQoJCQk8c25kVHJhbkRhdGU+MjAxMjA4MDE8L3NuZFRyYW5EYXRlPg0KICAgICAgICAgPC9jb250cm9sPg0KICAgICAgICAgPHJlcXVlc3Q+DQogICAgICAgICAgICA8c2V0VHJzTm8+MDAwMDAwMDAwMDAxPC9zZXRUcnNObz4NCgkJCTx0cnNDb2RlPjIwMTA1NDE8L3Ryc0NvZGU+DQoJCQk8c2V0UmN2U2V0QmtObz4wMDAwMDAwMDAwMDI8L3NldFJjdlNldEJrTm8+DQoJCQk8c2V0U25kU2V0QmtObz4wMDAwMDAwMDAwMDE8L3NldFNuZFNldEJrTm8+DQoJCQk8c2V0UmN2QmFua05vPjAwMDAwMDAwMDAwMjwvc2V0UmN2QmFua05vPg0KCQkJPHNldFNuZEJhbmtObz4wMDAwMDAwMDAwMDE8L3NldFNuZEJhbmtObz4NCgkJCTxzZXRUcnNEYXRlPjIwMTIwODAxPC9zZXRUcnNEYXRlPg0KICAgICAgICAgPC9yZXF1ZXN0Pg0KICAgICAgICAgPGV4dD4NCgkJCTxHWUg+MDAwMDAwMDAwMDAxPC9HWUg+DQoJCQk8WkhLSD4wMDAwMDAwMDAwMDAwMDAwMDAxPC9aSEtIPg0KCQkJPFpITUM+5byg5LiJPC9aSE1DPg0KCQkJPFpITFg+MTwvWkhMWD4NCgkJCTxaSkxYPjAwPC9aSkxYPg0KCQkJPFpKSE0+NDIyMjExMTk5MDEwMjQ5MTgwPC9aSkhNPg0KCQkJPEpZTU0+MTIzNDU2PC9KWU1NPg0KCQkJPFdZRExNPnpoYW5nc2FuPC9XWURMTT4NCgkJCTxXWURMTU0+MTIzNDU2PC9XWURMTU0+DQoJCQk8U1FSPmxpc2k8L1NRUj4NCgkJCTxXWURMRldYWD4xMjM0NTY3ODkwPC9XWURMRldYWD4NCgkJCTxLTEtYTEg+PC9LTEtYTEg+DQoJCTwvZXh0Pg0KICAgICAgPC9wb3J0OkFkZEV2YWx1YXRlSW5mbz4NCiAgIDwvc29hcGVudjpCb2R5Pg0KPC9zb2FwZW52OkVudmVsb3BlPg==";
	// System.out.println(new String(StringX.decodeBase64(str))+"\n\n\n");
	// System.out.println(StringX.byte2hex(StringX.decodeBase64(str))+"\n\n\n");
	// System.out.println(StringX.byte2hex("\r\n".getBytes())+"\n\n\n");
	// HTTPHeader header = new HTTPHeader();
	// byte[] content = unpack(StringX.decodeBase64(str), header);
	// System.out.println(header);
	// // System.out.println("\n\n\n" + new String(content));
	// System.out.println("\n\n\nkk:" + StringX.byte2hex(pack(header,
	// "abc".getBytes())));
	// System.out.println("\n\n\nkk:" + new String(pack(header,
	// "abc".getBytes())));
	// }

	public static byte[] packResponse(HTTPHeader header, byte[] content) throws Exception
	{
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos.write(HTTP_RESPONSE_HEADER);
		if (header != null) baos.write(header.params2str().getBytes());
		baos.write(HTTP_HEADER_CONTENT_LENGTH);
		baos.write(String.valueOf(content == null ? 0 : content.length).getBytes());
		baos.write(HTTP_HEAD_DELIM);
		baos.write(HTTP_HEAD_DELIM);
		if (content != null) baos.write(content);

		return baos.toByteArray();
	}

	public static byte[] unpackResponse(byte[] buf, HTTPHeader header)
	{
		StringBuffer str = new StringBuffer();
		int start = readLine(buf, 0, str); // read http
		String[] params = StringX.split(str.toString(), " ");
		header.protocol = params[0];
		header.statusCode = Integer.parseInt(params[1].trim());
		header.statusDesc = params[2];
		while (start < buf.length)
		{
			start = readLine(buf, start, str);
			String p = str.toString().trim();
			if (p.length() == 0) break; // last delim
			params = StringX.split(p, ":");
			header.params.put(params[0].trim(), params[1].trim());
		}
		if (start >= buf.length) return null;
		byte[] content = new byte[buf.length - start];
		System.arraycopy(buf, start, content, 0, content.length);
		return content;
	}

	public static byte[] packRequest(HTTPHeader header, byte[] content) throws Exception
	{
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		if (!StringX.nullity(header.method)) baos.write(header.method.getBytes());
		else baos.write(HTTP_POST);
		baos.write(' ');
		baos.write(header.uri.getBytes());
		baos.write(' ');
		if (!StringX.nullity(header.protocol)) baos.write(header.protocol.getBytes());
		else baos.write(HTTP_PROTOCOL_10);
		baos.write(HTTP_HEAD_DELIM); // http request line
		baos.write(header.params2str().getBytes());
		baos.write(HTTP_HEADER_CONTENT_LENGTH);
		baos.write(String.valueOf(content == null ? 0 : content.length).getBytes());
		baos.write(HTTP_HEAD_DELIM);
		baos.write(HTTP_HEAD_DELIM);
		baos.write(content);
		return baos.toByteArray();
	}

	public static byte[] unpackRequest(byte[] buf, HTTPHeader header)
	{
		int start = unpackRequestHeader(buf, header);
		if (start >= buf.length) return null;
		byte[] content = new byte[buf.length - start];
		System.arraycopy(buf, start, content, 0, content.length);
		return content;
	}

	public static int unpackRequestHeader(byte[] buf, HTTPHeader header)
	{
		return unpackRequestHeader(buf, buf.length, header);
	}

	public static int unpackRequestHeader(byte[] buf, int len, HTTPHeader header)
	{
		StringBuffer str = new StringBuffer();
		int start = readLine(buf, 0, str); // read http
		String[] params = StringX.split(str.toString(), " ");
		header.method = params[0];
		header.uri = params[1].trim();
		header.protocol = params[2].trim();
		while (start < len)
		{
			start = readLine(buf, start, str);
			String p = str.toString().trim();
			if (p.length() == 0) break; // last delim
			params = StringX.split(p, ":");
			header.params.put(params[0].trim(), params[1].trim());
		}
		return start;
	}

	public static int readLine(byte[] buf, int start, StringBuffer str)
	{
		str.setLength(0);
		while (start < buf.length)
		{
			if (buf[start] == '\r') return (start + 1 < buf.length && buf[start + 1] == '\n') ? start + 2
					: start + 1;
			str.append((char) buf[start++]);
		}
		return start;
	}
}
